<script setup lang="ts">
import type { MultipleConditionSearchSchema, Widgets } from './types'
import { Message } from '@arco-design/web-vue'
import { isFunction, set } from 'lodash-es'
import ContentTag from './components/ContentTag.vue'
import IconClear from './components/IconClear.vue'
import IconSearch from './components/IconSearch.vue'
import RenderWidget from './components/RenderWidget.vue'
import SearchCondition from './components/SearchCondition.vue'
import config from './config'
import { ProvideParamsSymbol, ProvideSchemaSymbol } from './types'

interface IEmit {
  (e: 'search'): void
}

interface IProps {
  schema: MultipleConditionSearchSchema
}

const props = defineProps<IProps>()
const emit = defineEmits<IEmit>()

const state = defineModel<Record<string, any>>({ required: true })
const isFocus = ref(false)

// 条件选择popover显示状态
const conditionVisible = ref(false)
// 当前选择的条件组件
const conditionWidget = ref<Widgets>()
// 已输入/选择的条件标签字段名
const contentFields = ref<string[]>([])

watchEffect(() => {
  isFocus.value = conditionVisible.value
})

/**
 * 根据已选择的条件过滤条件列表
 */
const filterWidgets = computed(() => {
  return props.schema.widgets.filter((item) => {
    return !contentFields.value.includes(item.field)
  })
})

function setState(key: string, value: any) {
  set(state.value, key, value)
}

/**
 * 处理条件选择选中
 * @param widget
 */
function handleChooseCondition(widget: Widgets) {
  conditionWidget.value = widget
}

/**
 * 处理条件选择popover隐藏
 */
function handleConditionHide() {
  conditionWidget.value = undefined
}

/**
 * 设置条件值
 * @param field 字段名
 * @param value 字段值
 * 注释内容在下方onSearch 中额外触发了一次
 */
function setCondition(field: string, value: any) {
  if (state.value[field] !== value && value) {
    setState(field, value)
  }
}

/**
 * 删除条件
 * @param field 字段名
 */
function deleteCondition(field: string) {
  const index = contentFields.value.findIndex(item => item === field)
  if (index >= 0) {
    contentFields.value.splice(index, 1)
  }
  setState(field, undefined)
  emit('search')
}

/**
 * 处理文本框直接输入，并设置配置的第一个type为input的字段
 * 逻辑已更换到 initContentFields 方法
 */
async function handleInputEnter(e: Event) {
  const el = e.target as HTMLInputElement
  const widget = filterWidgets.value.find(item => item.type === 'input')
  if (widget) {
    setCondition(widget.field, el.value)
    // const res = await checkValidate(widget, el.value)
    // if (res) {
    //   contentFields.value.push(widget.field)
    //   conditionVisible.value = false
    //   emit('search')
    // }
    // conditionVisible.value = false
    // emit('search')
  }
}
const searchInputRef = ref(null)

/**
 * 触发搜索
 * 逻辑已更换到 initContentFields 方法
 */
async function onSearch() {
  const widget = filterWidgets.value.find(item => item.type === 'input')
  const value = searchInputRef.value?.value || ''
  if (widget && value) {
    setCondition(widget.field, value)
  } else {
    emit('search')
  }
  // if (
  //   conditionWidget.value
  //   && !contentFields.value.includes(conditionWidget.value.field)
  // ) {
  //   // const res = await checkValidate(conditionWidget.value, state.value[conditionWidget.value.field])
  //   // if (res) {
  //   //   contentFields.value.push(conditionWidget.value.field)
  //   //   conditionVisible.value = false
  //   //   emit('search')
  //   // }
  //   // contentFields.value.push(conditionWidget.value.field)
  //   // conditionVisible.value = false
  //   // emit('search')
  // } else {
  //   emit('search')
  // }
}

/**
 * 重置搜索条件
 */
function reset() {
  const obj = { ...state.value }
  contentFields.value.forEach((field) => {
    set(obj, field, undefined)
  })
  contentFields.value = []
  state.value = obj
  emit('search')
}

/**
 * 初始化配置中的select的选项列表
 */
function initSelectOptions() {
  props.schema.widgets.forEach(async (widget) => {
    if (widget.type === 'select') {
      if (Array.isArray(widget.options)) {
        widget._optionsData = widget.options
        return
      }
      widget._optionsData = await widget.options()
    }
  })
}

/**
 * 判断正则
 * 对于没过正则验证的方法，删除该查询条件+参数
 */
async function checkValidate(widget: Widgets, fieldVal: string) {
  if (isFunction(widget.validate)) {
    const flag = (await widget?.validate?.(fieldVal)) || false
    if (flag) {
      setCondition(widget.field, fieldVal)
      return true
    } else {
      Message.error(widget.message || '请输入有效值')
      // setCondition(widget.field, undefined)
      contentFields.value.splice(contentFields.value.indexOf(widget.field), 1)
      set(state.value, widget.field, undefined)
      return false
    }
  }
  return true
}

/**
 * 根据state对应字段的值设置显示的条件标签
 * 查询功能也集合到此方法，任意修改值后，均会触发，之前进行正则验证，如果没过则删除该条件并进行一次查询
 */
async function initContentFields() {
  props.schema.widgets.forEach(async (widget) => {
    const fieldVal = state.value?.[widget.field]
    if (fieldVal !== undefined) {
      const res = await checkValidate(widget, fieldVal)
      if (res) {
        setCondition(widget.field, fieldVal)
        if (!contentFields.value.includes(widget.field)) {
          contentFields.value.push(widget.field)
        }
        conditionVisible.value = false
      }
      emit('search')
      // setCondition(widget.field, fieldVal)
    }
  })
}

function init() {
  contentFields.value = []
  initContentFields()
  initSelectOptions()
}
watch(
  () => props.schema,
  () => {
    init()
  },
  { deep: true, immediate: true },
)

// 值变更后，重新初始化标签显示
watch(
  state,
  () => {
    initContentFields()
  },
  { deep: true },
)

provide(ProvideParamsSymbol, state)
provide(ProvideSchemaSymbol, props.schema)
defineExpose({ reset })
</script>

<template>
  <div
    class="multiple-condition-search"
    :class="{
      'multiple-condition-search__focus': isFocus,
    }"
    :style="{
      minWidth: `${schema.minWidth || config.minWidth}px`,
      maxWidth: `${schema.maxWidth || config.maxWidth}px`,
    }"
  >
    <a-trigger
      v-model:popup-visible="conditionVisible"
      trigger="click"
      position="bl"
      :disabled="!filterWidgets.length"
      :popup-offset="10"
      @hide="handleConditionHide"
    >
      <div class="multiple-condition-search__content">
        <template v-if="contentFields.length">
          <template
            v-for="field in contentFields"
            :key="field"
          >
            <content-tag
              :widget="schema.widgets.find(item => item.field === field)!"
              @search="onSearch"
              @delete="deleteCondition"
              @show="isFocus = true"
              @hide="isFocus = false"
              @click.stop
            />
          </template>
        </template>
        <input
          v-else
          ref="searchInputRef"
          class="default-input"
          :placeholder="schema.placeholder || config.defaultPlaceholder"
          @keydown.enter="handleInputEnter"
        >
      </div>
      <template #content>
        <search-condition
          v-if="!conditionWidget"
          :list="filterWidgets"
          @click="handleChooseCondition"
        />
        <template v-else>
          <render-widget
            :widget="conditionWidget"
            @search="onSearch"
          />
        </template>
      </template>
    </a-trigger>

    <div class="multiple-condition-search__action">
      <icon-clear
        v-show="contentFields.length > 0"
        class="action-item"
        @click="reset"
      />
      <icon-search
        class="action-item"
        @click="onSearch"
      />
    </div>
  </div>
</template>

<style scoped lang="less">
.multiple-condition-search {
  display: flex;
  //height: 32px;
  border: 1px solid #e5e6eb;
  border-radius: 8px;
  padding: 4px 10px;
  transition: all 0.2s ease-out;
  &__focus {
    border-color: #00a65b;
    box-shadow: 0px 0px 0px 2px #adedc8;
  }
  &:hover,
  &:active {
    border-color: #00a65b;
  }
  &__content {
    display: flex;
    flex: 1;
    flex-shrink: 0;
    margin-right: 8px;
    cursor: pointer;
    padding-right: 32px;
    white-space: nowrap;
    overflow-y: auto;
    width: 100%;
    flex-wrap: wrap;
    gap: 8px;

    &::-webkit-scrollbar {
      height: 0;
    }
    .default-input {
      width: 100%;
      height: 100%;
      outline: none;
      font-size: 12px;
      line-height: 12px;
    }
  }
  &__action {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    padding-right: 2px;
    .action-item {
      margin-right: 8px;
      color: #86909c;
      cursor: pointer;
      &:last-child {
        margin-right: 0;
      }
    }
  }
}
</style>
